
package at.fhj.itm.metadata.impl.postgres;

import at.fhj.itm.metadata.Column;
import at.fhj.itm.metadata.Constraint;
import at.fhj.itm.metadata.DepdendencyProvider;
import at.fhj.itm.metadata.MetaDataException;
import at.fhj.itm.metadata.MetadataItem;
import at.fhj.itm.metadata.MetadataProvider;
import at.fhj.itm.metadata.Sequence;
import at.fhj.itm.metadata.Table;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 *
 * @author Seuchter
 */
public class PostgresDependencyProvider implements DepdendencyProvider{

    private PostgresMetadataProvider metaDataProvider;
    private Connection connection;
    public PostgresDependencyProvider(final PostgresMetadataProvider provider, final
            Connection connection){
        this.metaDataProvider = provider;
        this.connection = connection;
    }

    @Override
	public Connection getConnection(){
    	return connection;
    }

    @Override
	public Set<PostgresColumn> getPrimaryKeyColumns(Table t){
    	PostgresTable table = requireType(PostgresTable.class, t);
    	Set<PostgresColumn> cols = new HashSet<PostgresColumn>();
    	
    	for(PostgresConstraint curConstraint : table.getConstraints()){
    		if(curConstraint.getConstraintType().
    				equals(Constraint.CONSTRAINT_TYPE_PRIMARY_KEY)){
    			cols.addAll(curConstraint.getConstraintColumns());
    		}
    	}
    	
    	
    	return cols; 
    }
    
    @SuppressWarnings("unchecked")
	private<T> T requireType(Class<T> expected, Object actual){
        if(expected.isAssignableFrom(actual.getClass())){
            return (T) actual;
        }
        throw new IllegalArgumentException("MetadataItem is not of required type: " + expected.getName());
    }



    public List<PostgresSequence> getDependingSequences(Table t) {
        PostgresTable table = requireType(PostgresTable.class, t);

        try{
            PreparedStatement stmt = connection.prepareStatement(MetadataQueries.
                    getQuery("getDependenciesFromTableOid"));

            stmt.setLong(1, table.getOid());
            stmt.setString(2, "S");
            ResultSet set = stmt.executeQuery();
            List<PostgresSequence> seqs = new ArrayList<PostgresSequence>();


            while(set.next()){
                List<String> seqNames = new ArrayList<String>();
                seqNames.add(set.getString("relname"));
                List<PostgresSequence> curSeqs =
                        metaDataProvider.getSequenceFromNames(seqNames);
                seqs.addAll(curSeqs);
            }

            stmt.close();
            set.close();
            return seqs;

        }
        catch(Exception ex){
            throw new MetaDataException("Error determining dependencies for table", ex);
        }

    }

    public List<PostgresConstraint> getDependingConstraint(Table t, Column c){
        PostgresTable table = requireType(PostgresTable.class, t);
        PostgresColumn column = requireType(PostgresColumn.class, c);
        List<PostgresConstraint> depConstraint = new ArrayList<PostgresConstraint>();

        List<PostgresConstraint> cons = table.getConstraints();
        for(PostgresConstraint curCon : cons){
           if(curCon.getConstraintColumns().contains(column)){
               depConstraint.add(curCon);
           }
        }
        return depConstraint;

    }

    public PostgresSequence getDependingSequences(Table t, Column c) {

        try{
            PreparedStatement stmt = connection.prepareStatement(MetadataQueries
                    .getQuery("querySerialForTableColumn"));
            
            stmt.setString(1,t.getName());
            stmt.setString(2, c.getName());
            
            ResultSet set = stmt.executeQuery();
            set.next();;
            
            String seqName = set.getString(1);
            set.close();
            stmt.close();

            if(seqName == null || seqName.isEmpty()){
                return null;
            }

            List<PostgresSequence> seqs = metaDataProvider.getSequenceFromNames(Arrays.asList(seqName));

            if(seqs.size() <= 0){
                return null;
            }

            return seqs.get(0);

            
        }
        catch(Exception ex){
            throw new MetaDataException("Error determining dependencies for column", ex);
        }

    }






}
